using DA.AnimGraph;
using OdinSerializer;
using System.Collections.Generic;
using System.Linq;

namespace DA.AnimGraph.Editor {
    internal class AGEClipboard {
        public enum CopyContentFormat {
            None,
            BlendTree,
        }

        public struct Board {
            public CopyContentFormat copyContentFormat;
            public AUID sourceAssetUuid;
            public List<byte[]> nodes; // odin 序列化后的 AGANode_NodeBase
            public List<AGA_Edge> edges;
            public Dictionary<AUID, AGA_Resources.Entry> resources;
            public Dictionary<AUID, byte[]> timelineData;

            public void Clear() {
                copyContentFormat = CopyContentFormat.None;
                nodes?.Clear();
                edges?.Clear();
            }

            public bool IsValid() {
                return copyContentFormat != CopyContentFormat.None
                       && nodes != null && nodes.Count != 0;
            }
        }

        Board board;

        public AGEClipboard() {
        }

        public void ClearCopys() {
            board.Clear();
        }

        public void Copy(AGEContext ageContext, CopyContentFormat copyContentFormat, List<AGANode_NodeBase> nodes, List<AGA_Edge> edges) {
            board.copyContentFormat = copyContentFormat;
            board.sourceAssetUuid = ageContext.uuid;
            board.nodes = nodes.Select(x => SerializationUtility.SerializeValue(x, DataFormat.JSON)).ToList();
            board.edges = edges;

            // 跨文件复制需要的东西
            board.resources = new Dictionary<AUID, AGA_Resources.Entry>();
            board.timelineData = new Dictionary<AUID, byte[]>();
            for (int i = 0; i < nodes.Count; i++) {
                var node = nodes[i];
                // 复制资源
                if (node is IResourceNode rNode) {
                    var resUuids = rNode.GetResources();
                    if (resUuids != null) {
                        for (int j = 0; j < resUuids.Length; j++) {
                            if (board.resources.ContainsKey(resUuids[j])) continue; // resUuids可能存在相同内容，需要去重
                            if (ageContext.resourceManager.GetResource(resUuids[j], out var res)) {
                                board.resources.Add(resUuids[j], res);
                            }
                        }
                    }
                }
                // 复制perk
                if (node is AGANode_FunctionBase fNode) {
                    if (fNode.perks != null) {
                        for (int j = 0; j < fNode.perks.Count; j++) {
                            var perk = fNode.perks[j];
                            // 分类处理perk
                            if (perk is AGAPerk_Timeline timeline) {
                                var m = timeline.model;
                                var timelineData = ageContext.timelineManager.CopyToSerializeData(m.timelineUuid);
                                board.timelineData.Add(m.timelineUuid, timelineData);
                            }
                        }
                    }
                }
            }
        }

        public void Paste(AGEContext ageContext, out List<AGANode_NodeBase> resultNodes, out List<AGA_Edge> resultEdges) {
            if (!board.IsValid()) {
                resultNodes = null;
                resultEdges = null;
                return;
            }

            // 跨文件复制先把相应的东西加入manager中
            bool isSameContext = ageContext.uuid == board.sourceAssetUuid;
            Dictionary<AUID, AUID> resUuidMapping = null; // 旧id, 新id
            Dictionary<AUID, AUID> timelineUuidMapping = null;
            if (!isSameContext) {
                // 资源
                resUuidMapping = ageContext.resourceManager.AddResourcesByEntries(board.resources.Values.ToList());
                // timeline
                timelineUuidMapping = new(board.timelineData.Count);
                foreach (var timelineKV in board.timelineData) {
                    var newUuid = ageContext.timelineManager.PasteFromSerializeData(timelineKV.Value);
                    timelineUuidMapping.Add(timelineKV.Key, newUuid);
                }
            }

            resultNodes = new(board.nodes.Count);
            Dictionary<AUID, AUID> uuidMapping = new(board.nodes.Count);
            for (int i = 0; i < board.nodes.Count; i++) {
                var newNode = SerializationUtility.DeserializeValue<AGANode_NodeBase>(board.nodes[i], DataFormat.JSON);
                // 替换 uuid
                var newNodeUuid = AUIDGenerator.Gen();
                uuidMapping.Add(newNode.uuid, newNodeUuid);
                newNode.uuid = newNodeUuid;
                resultNodes.Add(newNode);

                // 处理资源引用计数
                if (newNode is IResourceNode rNode) {
                    var resUuids = rNode.GetResources();
                    if (resUuids != null) {
                        if (isSameContext) {
                            foreach (var resUuid in resUuids) {
                                ageContext.resourceManager.AddResourceRefCount(resUuid);
                            }
                        } else {
                            rNode.ReplaceResourceAUID(resUuidMapping);
                            foreach (var resUuid in resUuids) {
                                var uuid = resUuidMapping[resUuid];
                                ageContext.resourceManager.AddResourceRefCount(uuid);
                            }
                        }
                    }
                }
                // 处理perk
                if (newNode is AGANode_FunctionBase fNode) {
                    if (fNode.perks != null) {
                        for (int j = 0; j < fNode.perks.Count; j++) {
                            var perk = fNode.perks[j];
                            // 分类处理
                            if (perk is AGAPerk_Timeline timeline) {
                                var m = timeline.model;
                                if (isSameContext) {
                                    var newTimelineUuid = ageContext.timelineManager.Duplicate(m.timelineUuid);
                                    m.timelineUuid = newTimelineUuid;
                                } else {
                                    m.timelineUuid = timelineUuidMapping[m.timelineUuid];
                                }
                            }
                        }
                    }
                }
            }
            // 替换edge的uuid
            resultEdges = null;
            if (board.edges != null && board.edges.Count != 0) {
                resultEdges = new List<AGA_Edge>(board.edges);
                for (int i = 0; i < resultEdges.Count; i++) {
                    var e = resultEdges[i];
                    e.inputNode = uuidMapping[e.inputNode];
                    e.outputNode = uuidMapping[e.outputNode];
                    resultEdges[i] = e;
                }
            }
        }

        public bool HasCopy(CopyContentFormat copyContentFormat) {
            return board.copyContentFormat == copyContentFormat;
        }
    }
}
